﻿using System;
using System.Collections.Generic;
using System.Text;

namespace AB.Common
{
    /// <summary>
    /// 密码生成器
    /// </summary>
    public class Password
    {
        int cycleLimit = 100000;
        /// <summary>
        /// 数字
        /// </summary>
        public string Number { get { return "0123456789"; } }
        /// <summary>
        /// 小写字母
        /// </summary>
        public string Lowercase { get { return "abcdefghijklmnopqrstuvwxyz"; } }
        /// <summary>
        /// 大写字母
        /// </summary>
        public string Capital { get { return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } }
        /// <summary>
        /// 特殊符号
        /// </summary>
        public string Punctuation { get { return @"{]?<`>-!_/&';=.#*:[$+(~,}@|%^)"; } }

        /// <summary>
        /// 创建密码（批量）
        /// </summary>
        /// <param name="length">密码长度</param>
        /// <param name="count">密码个数(一次最多1000个)</param>
        /// <param name="hasNumber">允许包含数字</param>
        /// <param name="hasLowercase">允许包含小写字母</param>
        /// <param name="hasCapital">允许包含大写字母</param>
        /// <param name="hasPunctuation">允许包含特殊符号</param>
        /// <param name="allowRepeat">允许重复出现</param>
        /// <param name="allowNext">允许相邻字符相同</param>
        /// <param name="exclude">不允许出现的字符</param>
        /// <returns>返回生成的密码集合，无法生成指定的密码个数时，返回可生成的密码集合</returns>
        public List<string> CreatePW(int length, int count, bool hasNumber = true, bool hasLowercase = true, bool hasCapital = true, bool hasPunctuation = true, bool allowRepeat = true, bool allowNext = true, List<char> exclude = null)
        {
            List<string> pwList = new List<string>();
            int createCount = 0;
            while (1001 > count && pwList.Count < count && createCount < cycleLimit)
            {
                string pw = CreatePW(length, hasNumber, hasLowercase, hasCapital, hasPunctuation, allowRepeat, allowNext, exclude);
                if (string.IsNullOrEmpty(pw))
                {
                    break;
                }
                if (pwList.Contains(pw))
                {
                    createCount++;
                    continue;
                }
                pwList.Add(pw);
                createCount = 0;
            }
            return pwList;
        }
        /// <summary>
        /// 创建密码
        /// </summary>
        /// <param name="length">密码长度</param>
        /// <param name="hasNumber">允许包含数字</param>
        /// <param name="hasLowercase">允许包含小写字母</param>
        /// <param name="hasCapital">允许包含大写字母</param>
        /// <param name="hasPunctuation">允许包含特殊符号</param>
        /// <param name="allowRepeat">允许重复出现</param>
        /// <param name="allowNext">允许相邻字符相同</param>
        /// <param name="exclude">不允许出现的字符</param>
        /// <returns>返回生成的密码，无法生成符合规则的密码时，返回Null</returns>
        public string CreatePW(int length, bool hasNumber = true, bool hasLowercase = true, bool hasCapital = true, bool hasPunctuation = true, bool allowRepeat = true, bool allowNext = true, List<char> exclude = null)
        {
            string pw = Create(length, hasNumber, hasLowercase, hasCapital, hasPunctuation, allowRepeat, allowNext, exclude);
            return pw;
        }
        /// <summary>
        /// 密码强度
        /// </summary>
        /// <param name="password">密码</param>
        /// <returns></returns>
        public PasswordStrength GetPasswordStrength(string password)
        {
            if (string.IsNullOrEmpty(password))
            {
                return 0;
            }
            int strength = 1;
            if (password.Length >= 6)
            {
                int iNum = 0, iLowercase = 0, iCapital = 0, iPunctuation = 0;
                foreach (char item in password)
                {
                    if (item >= '0' && item <= '9') iNum++;
                    else if (item >= 'a' && item <= 'z') iLowercase++;
                    else if (item >= 'A' && item <= 'Z') iCapital++;
                    else iPunctuation++;
                }
                if (iNum > 0) strength++;
                if (iLowercase > 0) strength++;
                if (iCapital > 0) strength++;
                if (iPunctuation > 0) strength++;
            }
            return (PasswordStrength)strength;
        }
        /// <summary>
        /// 验证是否可以生成密码
        /// </summary>
        /// <param name="length">密码长度</param>
        /// <param name="count">需要生成的密码个数</param>
        /// <param name="hasNumber">允许包含数字</param>
        /// <param name="hasLowercase">允许包含小写字母</param>
        /// <param name="hasCapital">允许包含大写字母</param>
        /// <param name="hasPunctuation">允许包含特殊符号</param>
        /// <param name="frequency">允许单个字符出现的次数,小于1为不受限</param>
        /// <param name="allownext">允许相邻字符相同</param>
        /// <param name="exclude">不允许出现的字符</param>
        /// <returns></returns>
        private bool ValidCheck(int length, int count, bool hasNumber, bool hasLowercase, bool hasCapital, bool hasPunctuation, int frequency, bool allownext, List<char> exclude)
        {
            //StringBuilder candidate = GetCandidate(hasNumber, hasLowercase, hasCapital, hasPunctuation, exclude);
            //int CharCount = candidate.Length;
            //int PwCount = 1;
            //for (int index = 1; index <= length; index++)
            //{
            //    int indexCount = CharCount;
            //    if (!allownext&&index!=1)
            //    {
            //        indexCount--;
            //    }
            //    if (frequency>0&&index!=1)
            //    {

            //    }
            //    if (indexCount < 1)
            //    {
            //        return false;
            //    }
            //    PwCount = PwCount * indexCount;
            //}
            //frequency = allownext ? (frequency > length ? length : frequency) : frequency > (int)Math.Ceiling(length * 1.0 / 2) ?(int)Math.Ceiling(length * 1.0 / 2) : frequency;
            //if (frequency>0)
            //{

            //}
            return true;
        }
        /// <summary>
        /// 创建密码
        /// </summary>
        /// <param name="length">密码长度</param>
        /// <param name="hasNumber">允许包含数字</param>
        /// <param name="hasLowercase">允许包含小写字母</param>
        /// <param name="hasCapital">允许包含大写字母</param>
        /// <param name="hasPunctuation">允许包含特殊符号</param>
        /// <param name="allowRepeat">允许重复出现</param>
        /// <param name="allowNext">允许相邻字符相同</param>
        /// <param name="exclude">不允许出现的字符</param>
        /// <returns></returns>
        private string Create(int length, bool hasNumber, bool hasLowercase, bool hasCapital, bool hasPunctuation, bool allowRepeat, bool allowNext, List<char> exclude)
        {
            StringBuilder pwd = new StringBuilder();
            StringBuilder candidate = GetCandidate(hasNumber, hasLowercase, hasCapital, hasPunctuation, exclude);
            string last = "";
            //int getCharCount = 0;
            while (pwd.Length < length)
            {
                StringBuilder candidatestr = new StringBuilder(candidate.ToString());
                if (!allowNext && !string.IsNullOrEmpty(last))
                {
                    candidatestr = candidatestr.Replace(last, "");
                }
                string c = GetChar(candidatestr);
                if (c != null)
                {
                    //if (frequency > 0)
                    //{
                    //    int count = pwd.Length - pwd.Replace(c, "").Length + 1;
                    //    if (count > frequency)
                    //    {
                    //        getCharCount++;
                    //        if (getCharCount > cycleLimit)
                    //        {
                    //            return null;
                    //        }
                    //        continue;
                    //    }
                    //}
                    if (!allowRepeat)
                    {
                        candidate = candidate.Replace(c, "");
                    }
                    pwd.Append(c);
                    last = c;
                    //getCharCount = 0;
                }
                else
                {
                    return null;
                }
            }
            return pwd.ToString(0, length);
        }
        /// <summary>
        /// 获取所有候选字符
        /// </summary>
        /// <returns></returns>
        private StringBuilder GetCandidate(bool hasNumber, bool hasLowercase, bool hasCapital, bool hasPunctuation, List<char> exclude)
        {
            StringBuilder candidate = new StringBuilder();
            if (hasNumber)
            {
                candidate.Append(Number);
            }
            if (hasLowercase)
            {
                candidate.Append(Lowercase);
            }
            if (hasCapital)
            {
                candidate.Append(Capital);
            }
            if (hasPunctuation)
            {
                candidate.Append(Punctuation);
            }
            if (exclude != null && exclude.Count > 0)
            {
                foreach (var item in exclude)
                {
                    candidate = candidate.Replace(item.ToString(), "");
                }
            }
            return candidate;
        }
        Random ra = new Random(unchecked((int)DateTime.Now.Ticks));
        /// <summary>
        /// 获取候选字符中的一个字符
        /// </summary>
        /// <param name="candidate">候选字符</param>
        /// <returns></returns>
        private string GetChar(StringBuilder candidate)
        {
            if (candidate!=null&& candidate.Length>0)
            {
                int length = candidate.Length;
                int index = ra.Next(0, length);
                return candidate[index].ToString();
            }
            return null;
        }
    }

    /// <summary>
    /// 密码强度
    /// </summary>
    public enum PasswordStrength
    {
        /// <summary>
        /// 空
        /// </summary>
        Invalid = 0,
        /// <summary>
        /// 很弱
        /// </summary>
        VWeek = 1,
        /// <summary>
        /// 弱
        /// </summary>
        Week = 2,
        /// <summary>
        /// 正常
        /// </summary>
        Normal = 3,
        /// <summary>
        /// 强
        /// </summary>
        Strong = 4,
        /// <summary>
        /// 极强
        /// </summary>
        VStrong = 5
    }
}
